package com.kinyx.framework.utils;

import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Predicate;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.ReturnNull;
import com.kinyx.framework.exception.KRuntimeException;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 枚举工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KEnumUtils {

	/**
	 * 取枚举序号
	 * @param e 枚举对象
	 * @return 枚举序号
	 */
	public static int ordinal(@CanNotNull final Object e) {
		try {
			return (int) e.getClass().getMethod("ordinal").invoke(e);
		} catch (final Exception ex) {
			throw new KRuntimeException(ex);
		}
	}

	/**
	 * 遍历枚举对象
	 * @param <T> 枚举类型
	 * @param clazz 枚举类型
	 * @param handler 处理方法
	 */
	public static <T> void iterator(@CanNotNull final Class<T> clazz, @CanNotNull final Consumer<T> handler) {
		Arrays.asList(clazz.getEnumConstants()).forEach(enumValue -> { handler.accept(enumValue); });
	}

	/**
	 * 遍历枚举对象并返回比对成功的值
	 * @param <T> 枚举类型
	 * @param clazz 枚举类型
	 * @param comparator 对比方法
	 * @return 枚举对象
	 */
	@ReturnNull("未匹配到枚举")
	public static <T> T compare(@CanNotNull final Class<T> clazz, @CanNotNull final Predicate<T> comparator) {
		final T[] enumValues = clazz.getEnumConstants();
		for (final T enumValue : enumValues) {
			if (comparator.test(enumValue)) { return enumValue; }
		}
		return null;
	}

	/**
	 * 遍历枚举对象并返回比对成功的值
	 * @param <T> 枚举类型
	 * @param clazz 枚举类型
	 * @param ordinal 枚举序号
	 * @return 枚举对象
	 */
	@ReturnNull("未匹配到枚举")
	public static <T> T compare(@CanNotNull final Class<T> clazz, @CanNotNull final int ordinal) {
		return compare(clazz, e -> {
			return Integer.valueOf(ordinal).equals(ordinal(e));
		});
	}

	/**
	 * 取正则表达式
	 * @param <T> 泛型
	 * @param clazz 枚举类型
	 * @return 正则表达式
	 */
	@ReturnNotNull
	public static <T> String getRegex(@CanNotNull final Class<T> clazz) {
		final T[] enumValues = clazz.getEnumConstants();
		final int iMax = enumValues.length - 1;
		final StringBuilder sb = new StringBuilder("(");
		for (int i = 0;; i++) {
			final T value = enumValues[i];
			sb.append(value.toString());
			if (i == iMax) { return sb.append("){1}").toString(); }
			sb.append("|");
		}
	}

}
